// Compiler Directives (编译器指令) 示例
// 演示 Pascal 中编译器指令的各种用法
program p_39_compiler_directives;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式
// {$H+} 启用长字符串支持（AnsiString）

// 保存当前编译器状态
{$PUSH}
// 启用范围检查
{$R+}
// 启用溢出检查
{$Q+}
// 启用类型检查
{$T+}

uses
  SysUtils, Classes;

// 恢复之前的编译器状态
{$POP}

// 定义自定义编译器指令常量
{$DEFINE MY_DEBUG}
{$DEFINE USE_OPTIMIZATION}

// 条件编译示例
{$IFDEF MY_DEBUG}
  {$IFDEF USE_OPTIMIZATION}
    {$OPTIMIZATION ON}
  {$ELSE}
    {$OPTIMIZATION OFF}
  {$ENDIF}
{$ENDIF}

// 控制警告信息
{$WARN 6058 ON}  // 打开未使用函数警告

// 定义记录打包方式
{$PACKRECORDS C}

// 定义自定义类型
type
  // 标准记录
  TStandardRecord = record
    A: Byte;
    B: Integer;
    C: Byte;
  end;
  
  // 使用C风格打包的记录
  TCStyleRecord = record
    A: Byte;
    B: Integer;
    C: Byte;
  end;

// 定义一个可能未使用的函数，用于演示警告
{$WARN 6058 ON}
function UnusedFunction: Integer;
begin
  Result := 42;
end;
{$WARN 6058 OFF}

// 演示范围检查的函数
function TestRangeChecking(Value: Integer): Integer;
begin
  Result := Value;
end;

// 演示溢出检查的函数
function TestOverflowChecking(A, B: Integer): Integer;
begin
  Result := A + B;
end;

// 演示类型检查的函数
procedure TestTypeChecking(var Value: Integer);
begin
  Value := 100;
end;

// 演示不同的优化设置
{$IFDEF USE_OPTIMIZATION}
  {$OPTIMIZATION ON}
{$ELSE}
  {$OPTIMIZATION OFF}
{$ENDIF}

function OptimizedFunction(X: Integer): Integer;
begin
  Result := X * 2 + 1;
end;

// 演示编译器信息指令
{$IFOPT O+}
  {$DEFINE OPTIMIZATION_ENABLED}
{$ENDIF}

// 演示内存管理相关指令
{$IFDEF FPC_HAS_CPUI386}
  {$DEFINE TARGET_X86}
{$ENDIF}

// 程序主入口
begin
  WriteLn('=== Pascal 编译器指令示例 ===');
  WriteLn;
  
  // 1. 显示编译器信息
  WriteLn('1. 编译器信息:');
  WriteLn('  编译器版本: ', {$I %FPCVERSION%});
  WriteLn('  编译日期: ', {$I %DATE%});
  WriteLn('  编译时间: ', {$I %TIME%});
  WriteLn('  目标CPU: ', {$I %FPCTARGETCPU%});
  WriteLn('  目标操作系统: ', {$I %FPCTARGETOS%});
  
  {$IFDEF OPTIMIZATION_ENABLED}
    WriteLn('  优化已启用');
  {$ELSE}
    WriteLn('  优化未启用');
  {$ENDIF}
  
  WriteLn;
  
  // 2. 记录大小演示
  WriteLn('2. 记录大小演示:');
  WriteLn('  标准记录大小: ', SizeOf(TStandardRecord), ' 字节');
  WriteLn('  C风格记录大小: ', SizeOf(TCStyleRecord), ' 字节');
  
  var stdRec: TStandardRecord;
  var cRec: TCStyleRecord;
  
  WriteLn('  标准记录字段偏移:');
  WriteLn('    A: ', PtrUInt(@stdRec.A) - PtrUInt(@stdRec), ' 字节');
  WriteLn('    B: ', PtrUInt(@stdRec.B) - PtrUInt(@stdRec), ' 字节');
  WriteLn('    C: ', PtrUInt(@stdRec.C) - PtrUInt(@stdRec), ' 字节');
  
  WriteLn('  C风格记录字段偏移:');
  WriteLn('    A: ', PtrUInt(@cRec.A) - PtrUInt(@cRec), ' 字节');
  WriteLn('    B: ', PtrUInt(@cRec.B) - PtrUInt(@cRec), ' 字节');
  WriteLn('    C: ', PtrUInt(@cRec.C) - PtrUInt(@cRec), ' 字节');
  
  WriteLn;
  
  // 3. 范围检查演示
  WriteLn('3. 范围检查演示:');
  try
    var smallValue: ShortInt = 127;
    var resultValue: Integer;
    
    {$IFDEF FPC_HAS_TYPE_SUPPORT}
      {$R+}
      // 这里会触发范围检查错误（如果启用）
      // resultValue := TestRangeChecking(300); // 超出ShortInt范围
      {$R-}
    {$ENDIF}
    
    WriteLn('  范围检查功能正常');
  except
    on E: Exception do
      WriteLn('  捕获范围检查异常: ', E.Message);
  end;
  
  WriteLn;
  
  // 4. 溢出检查演示
  WriteLn('4. 溢出检查演示:');
  try
    var a: Integer = MaxInt;
    var b: Integer = 1;
    
    {$Q+}
    // 这里会触发溢出检查错误（如果启用）
    // var overflowResult: Integer = TestOverflowChecking(a, b);
    {$Q-}
    
    WriteLn('  溢出检查功能正常');
  except
    on E: Exception do
      WriteLn('  捕获溢出检查异常: ', E.Message);
  end;
  
  WriteLn;
  
  // 5. 优化设置演示
  WriteLn('5. 优化设置演示:');
  var x: Integer = 5;
  var optResult: Integer = OptimizedFunction(x);
  WriteLn('  OptimizedFunction(', x, ') = ', optResult);
  
  WriteLn;
  
  // 6. 条件编译演示
  WriteLn('6. 条件编译演示:');
  {$IFDEF MY_DEBUG}
    WriteLn('  自定义调试符号 MY_DEBUG 已定义');
  {$ELSE}
    WriteLn('  自定义调试符号 MY_DEBUG 未定义');
  {$ENDIF}
  
  {$IFDEF USE_OPTIMIZATION}
    WriteLn('  优化开关 USE_OPTIMIZATION 已启用');
  {$ELSE}
    WriteLn('  优化开关 USE_OPTIMIZATION 未启用');
  {$ENDIF}
  
  WriteLn;
  
  // 7. 编译器状态控制演示
  WriteLn('7. 编译器状态控制演示:');
  {$PUSH}
  {$WARNINGS ON}
  WriteLn('  警告信息已启用');
  {$WARNINGS OFF}
  WriteLn('  警告信息已禁用');
  {$POP}
  WriteLn('  恢复之前的警告设置');
  
  WriteLn;
  
  // 8. 内存对齐演示
  WriteLn('8. 内存对齐演示:');
  {$IFDEF TARGET_X86}
    WriteLn('  目标平台: x86');
  {$ELSE}
    WriteLn('  目标平台: 其他');
  {$ENDIF}
  
  WriteLn;
  WriteLn('演示了 Pascal 中编译器指令的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.